#include "net/signal.h"
#include <sys/signalfd.h>
#include <signal.h>

namespace net {
void SigHandler(int fd, void* arg, int /*event*/) {
  PCHECK(fd > 0);
  SigManager* sig_manager = (SigManager*) arg;

  struct signalfd_siginfo info;
  ::memset(&info, 0, sizeof(info));
  ssize_t readn = ::read(fd, &info, sizeof(info));
  if (readn == -1) {
    if (errno != EAGAIN) {
      PLOG(WARNING)<< "read from signal fd error";
    }
    return;
  }

  sig_manager->HandleSignal(info.ssi_signo);
}

SigManager::SigManager(Poller* poller)
    : poller_(poller), sig_fd_(-1) {
  CHECK(poller_ != NULL);
}

SigManager* SigManager::instance_ = NULL;

Signal* SigManager::RegSig(int32 signo) {
  Signal* sig = new Signal;
  sig->signo = signo;
  sig->cb = NULL;
  sig->ctx = NULL;

  sig_map_[signo] = sig;
  return sig;
}

void SigManager::HandleSignal(int32 signo) {
  std::map<int, Signal*>::iterator it = sig_map_.find(signo);
  if (it == sig_map_.end()) {
    LOG(WARNING)<< "unknown signo: " << signo;
    return;
  }

  LOG(INFO)<< "catch signal, number: " << signo;
  Signal* sig = it->second;
  if (sig->cb) {
    sig->cb(sig->ctx);
  }
}

void SigManager::Start() {
  CHECK(sig_fd_ == -1);
  sigset_t mask;
  ::sigemptyset(&mask);
  for (std::map<int, Signal*>::iterator it = sig_map_.begin();
      it != sig_map_.end(); ++it) {
    Signal* sig = it->second;
    if (!sig->cb) continue;
    ::sigaddset(&mask, sig->signo);
  }

  int ret = ::sigprocmask(SIG_BLOCK, &mask, NULL);
  PCHECK(ret != -1) << "sigprocmask error";

  sig_fd_ = ::signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
  PCHECK(sig_fd_ != -1) << "signalfd error";

  sig_ev_.fd = sig_fd_;
  sig_ev_.cb = SigHandler;
  sig_ev_.arg = this;
  sig_ev_.event = EV_READ;

  CHECK(poller_->Add(&sig_ev_, sig_ev_.event));
}
}
